這次我們試用直接透過SDK的Dynamo Client進行項目操作。
針對Table的操作都很簡單,我們需要建立DynamoDB Client供DynamoDB Table使用。
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "us-west-2"))
.build();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable("table1");
因為打算要連線的是DynamoDB-Local,所以要指定EndpointConfitguration,那如果要使用AWS雲端服務呢,就不需要指定了。
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
在不指定的情況下,Lambda連線的資料庫就是開發環境下AWS CLI設定的regions,在AWS雲端上執行的Lambda,就是使用與Lambda相同regions的DynamoDB
但是如果你實際連線DynamoDB-Local時發生socket refuse connection ,代表你跟我遇到一樣的問題。,那麼EndpointConfiguration請改用你環境local ip address或是使用alias ip address導向本機 。例如我的環境VirtualBox&Ubuntu,Ubuntu當中以ip address show查詢其中網卡enp0s3使用的位置是10.0.2.15。那麼EndpointConfiguration設定為http://10.0.2.15:8000 即可。
首先我希望使用PUT /person來處理建立項目的方法,在template.yaml當中補上之前沒有的內容於UpdatePerson Events當中
CreatePerson:
Type: Api
Properties:
Path: /person
Method: PUT
原本的updatePerson method當中path variable person_id判斷無值時回傳http500的邏輯拿掉,然後在if判斷httpMethod為PUT之中增加若無person_id則產生一個
if (StringUtils.isNullOrEmpty(person_id))
person_id = UUID.randomUUID().toString();
接下來就是前面起手式那段取得DynamoDB Table後,進行putItem的操作
PutItemOutcome outcome = table.putItem(new Item().withPrimaryKey("pk_id", person_id)
.withString("firstName", person.getFirstName())
.withString("lastName", person.getLastName()) );
context.getLogger().log("PutItemOutcome:" + outcome.getPutItemResult().toString() + "\n");
person.setId(person_id);
return new ResponseBean(pseron, Views.idOnly.class);
(因為每個想要填值的屬性,操作時都要一個個塞值,所以這邊偷懶只處理pk_id與兩個屬性)
最後使用JsonView的技巧僅回傳新項目的id內容。
透過PostMan進行簡單測試,使用PUT /person並給予如下JSON
{"firstName": "Spencer", "lastName": "Liu", "email": "spencer@somwhere.com"}
不過當然,實際上只有firstName、lastName會存入資料庫。
成功時即取得新增項目的id
{
"id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd"
}
這邊用Get /person/{person_id} 來實作getItem。在queryPerson當中person_id判斷有值的段落增加起手式取得table及以下code
Item outcome = table.getItem(new GetItemSpec().withPrimaryKey("pk_id", person_id));
context.getLogger().log("item:" + outcome.toJSONPretty() + "\n");
Person person = new Person();
person.setId(outcome.getString("pk_id"));
person.setFirstName(outcome.getString("firstName"));
person.setLastName(outcome.getString("lastName"));
return new ResponseBean(person, View.Public.class);
這樣當我們使用get /person/069ee1b0-2a2b-4d7b-80e3-1367d16323fd
在log當中我們會看到
item:{
"firstName" : "Spencer",
"lastName" : "Liu",
"pk_id" : "069ee1b0-2a2b-4d7b-80e3-1367d16323fd"
}
在response當中會看到
{
"id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd",
"firstName": "Spencer",
"lastName": "Liu",
"email": null,
"phone": null,
"gender": null
}
喔 等等,或許也可以改寫Jackson參數讓null不顯示出來,在ResponseBean.getBody中使用ObjectMapper之前設定
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
這樣response會變成
{
"id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd",
"firstName": "Spencer",
"lastName": "Liu"
}
UpdateItem與PutItem就很類似了,我們在updatePerson當中處理POST /person/{person_id}的部分增加以下內容
if (StringUtils.isNullOrEmpty(person_id))
return new ResponseBean(500);
/*
這邊填入起手式取得Table的部分
*/
String setStr = "";
ValueMap valueMap = new ValueMap();
if (!StringUtils.isNullOrEmpty(person.getFirstName())) {
setStr = "firstName = :firstName";
valueMap.withString(":firstName", person.getFirstName());
}
if (!StringUtils.isNullOrEmpty(person.getLastName())) {
if (StringUtils.isNullOrEmpty(setStr))
setStr = "lastName = :lastName";
else setStr = setStr + ", lastName = :lastName";
valueMap.withString(":lastName", person.getLastName());
}
if (StringUtils.isNullOrEmpty(setStr))
return new ResponseBean(500);
UpdateItemSpec spec = new UpdateItemSpec().withPrimaryKey("pk_id", person_id)
.withUpdateExpression("set " + setStr)
.withValueMap(valueMap)
.withReturnValues(ReturnValue.ALL_NEW);
UpdateItemOutcome outcome = table.updateItem(spec);
context.getLogger().log("PutItemOutcome:" + outcome.getUpdateItemResult().toString() + "\n");
person.setId(outcome.getItem().getString("pk_id"));
person.setFirstName(outcome.getItem().getString("firstName"));
person.setLastName(outcome.getItem().getString("lastName"));
return new ResponseBean(person, Views.Public.class);
我們測試用POST /person/069ee1b0-2a2b-4d7b-80e3-1367d16323fd
並且JSON內容使用
{"firstName": "Jack"}
更新完成後會得到完整的response,這是因為使用了ReturnValue.ALL_NEW
{
"id": "069ee1b0-2a2b-4d7b-80e3-1367d16323fd",
"firstName": "Jack",
"lastName": "Liu"
}
刪除項目相對來說就簡單多了,在處理DELETE /person/{person_id}的deletePerson當中增加起手式及以下內容
table.deleteItem(new DeleteItemSpec().withPrimaryKey(new PrimaryKey("pk_id", person_id)));
return new ResponseBean(200);
試試執行刪除,然後再嘗試取得Item就找不到資料了
經過初步的嘗試,會發現這樣操作存取項目會需要一個個處理所有屬性,相對來說每次不同的作業都要重複處理大量的程式碼。不過接下來我們會嘗試AWS SDK提供的物件持久性模型,會更容易將定義好的bean對應dynamodb項目操作。
而上述程式碼僅為了簡易測試,對於邏輯判斷及省略了錯誤處理,如果要正式實作記得要再加上喔。